//###############
//FILE : Session.java
//WRITER : Daniel Lowengrub, daniel_i_l, 320687098
//EXERCISE : oop ex3 2011
//DESCRIPTION:
//See below
//###############
package oop.ex3.protocol.sessions;

import oop.ex3.protocol.messages.EndListMsg;
import oop.ex3.protocol.messages.EndSessionMsg;
import oop.ex3.protocol.messages.Message;
import oop.ex3.protocol.messages.DoneMsg;
import oop.ex3.protocol.messages.WelcomeMsg;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import oop.ex3.exceptions.InvalidMessageException;
import oop.ex3.protocol.messages.ErrorMsg;

/**
 * This is the base class for all sessions. A session is a predetermined sequence of messages
 * that are sent over a data stream. Most sessions have a specific task to carry out or a certain
 * piece of information to send or receive.
 * It implements functionality common to all sessions.
 * All base classes have to implement the specExecuteSession method which provide session specific
 * execution behavior.
 * @author daniel
 */
public abstract class Session {
    protected Message _initialMessage;

    protected static Message _done = new DoneMsg();
    protected static Message _endList = new EndListMsg();
    protected static Message _welcome = new WelcomeMsg();
    protected static Message _endSession = new EndSessionMsg();
    protected static Message _errorMsg = new ErrorMsg();
    
    /**
     * Create a new session with a certain initial message. This is the message that will be
     * used to check if a certain data stream can be handled by this session.
     * @param initialMessage The initial message.
     */
    public Session(Message initialMessage) {
        _initialMessage = initialMessage;
    }

    /**
     * Check if a given data stream can be handled by this session.
     * @param inputStream The data strem to check.
     * @return True iff this session can handle the stream.
     * @throws IOException If there was a problem with the stream.
     */
    public boolean matchInput(DataInputStream inputStream) throws IOException {
        boolean output =  _initialMessage.matchHeader(inputStream);
        return output;
    }

    /**
     * Run the specExecuteSession method check for errors. If there were errors then run the
     * cleanup method and return false. Otherwise return true.
     * @param inputStream The sending stream.
     * @param outputStream The receiving stream.
     * @return True iff the execution was successful.
     */
    public boolean executeSession(DataInputStream inputStream,
            DataOutputStream outputStream) {
        boolean output;
        
        try {
            output = specExecuteSession(inputStream, outputStream);
        } catch (Exception ex) {
            cleanup(outputStream);
            //ex.printStackTrace();
            return false;
        }
        
        return output;
    }

    /**
     * Here the implementing class puts session specific executing commands.
     * @param inputStream The sending stream.
     * @param outputStream The receiving stream.
     * @return True iff the execution was successful.
     * @throws IOException If there was  problem sending / receiving the data.
     * @throws InvalidMessageException If an unexpected message was encountered.
     */
    protected abstract boolean specExecuteSession(DataInputStream inputStream,
            DataOutputStream outputStream) throws IOException, InvalidMessageException;

    /**
     * This method is run if execution fails.
     * @param outputStream The stream that can be used to send cleanup commands such as ERROR.
     */
    protected void cleanup(DataOutputStream outputStream) {/*empty default implementation*/}
}
